<template>
  <WebGLCanvas :id="id"/>
</template>

<script setup lang="ts">
  import { Engine, Scene, ArcRotateCamera, UniversalCamera, Vector3,
    HemisphericLight, PointLight, DirectionalLight, SpotLight,
    MeshBuilder, Color3, 
    StandardMaterial, Texture
  } from '@babylonjs/core'
  import SongYi from '~/assets/images/babylon/songyi.jpg'
  import Star from '~/assets/images/babylon/star.jpg'

  const id = 'lights'
  useHead({
    title: '灯光-学会为物体打光'
  })

  const initBabylon = () => {
    // 初始化canvas
    const canvas = document.querySelector<HTMLCanvasElement>(`#${id}`)
    if (!canvas) {
      throw new Error('Canvas not found.')
    }
    canvas.width = window.innerWidth
    canvas.height = window.innerHeight
    // 初始化babylon 3D Engine, 开启抗锯齿
    /** 
     * “抗锯齿(英语:anti-aliasing,简称AA),
     * 也译为边缘柔化、消除混叠、抗图像折叠有损等。
     * 它是一种消除显示器输出的画面中图物边缘出现凹凸锯齿的技术,
     * 那些凹凸的锯齿通常因为高分辨率的信号以低分辨率表示或无法准确运算出3D图形坐标定位时所导致的图形混叠(aliasing)而产生的,
     * 反锯齿技术能有效地解决这些问题。
     */
    const engine = new Engine(canvas, true)

    // 创建一个场景
    const scene = new Scene(engine)
    // 要看到漫反射和镜面反射的材质效果，必须要求创建至少一个光源。
    // 要让环境背光照射出材质的环境颜色效果，还需要为场景设置一个环境颜色
    // scene.ambientColor = new Color3(0.1, 0.4, 1)

    // 添加一个通用相机
    const camera = new UniversalCamera(
      'camera',
      new Vector3(0, 0, -10),
      scene
    )

    // 添加一个弧形旋转相机
    // const camera = new ArcRotateCamera(
    //   'camera',
    //   0,
    //   0,
    //   20,
    //   new Vector3(0, 0, 0),
    //   scene
    // )
    // camera.setPosition(new Vector3(0, 0, 10))

    // 绑定鼠标事件
    camera.attachControl(canvas, true)
    // 添加一组灯光到场景
    // 半球光是模拟环境光的简便方法
    // const light1 = new HemisphericLight('light1', new Vector3(1, 1, 0), scene)
    // const light2 = new PointLight('light2', new Vector3(0, 1, -1), scene)
    // const light3 = new DirectionalLight('light3', new Vector3(0, -1, 0), scene)
    // 聚光灯由位置position，方向direction，角度angle和指数exponent定义。
    // 上面的数值决定了圆锥形光束该从什么位置开始，然后朝哪个方向照射。
    const light4 = new SpotLight(
      'light4',
      new Vector3(0, 30, -10),
      new Vector3(0, -1, 0),
      Math.PI / 3,
      2,
      scene
    )
    // 添加一个球体到场景中
    // const sphere = MeshBuilder.CreateSphere('sphere', {diameter: 1}, scene)
    // sphere.position = new Vector3(0, 0, 0)
    
    // 创建一个胶囊
    const capsule = MeshBuilder.CreateCapsule('capsule', {}, scene)

    // 创建一个材质
    const materials = new StandardMaterial('material', scene)
    // 漫反射颜色
    // materials.diffuseColor = new Color3(1, 0, 1)
    // 镜面颜色
    // materials.specularColor = new Color3(0.5, 0.6, 0.87)
    // 自发光颜色
    materials.emissiveColor = new Color3(0.18, 0.35, 0.68)
    // 环境光颜色
    // materials.ambientColor = new Color3(0.23, 0.98, 0.53)

    capsule.material = materials

    // 创建一个ico球体
    const icoSphere = MeshBuilder.CreateIcoSphere('icoSphere', {}, scene)
    icoSphere.position = new Vector3(2, 0, 0)

    const icoMaterail = new StandardMaterial('icoMaterail', scene)

    icoMaterail.diffuseTexture = new Texture(Star, scene)
    icoMaterail.specularTexture = new Texture(Star, scene)
    icoMaterail.emissiveTexture = new Texture(Star, scene)
    icoMaterail.ambientTexture = new Texture(Star, scene)

    icoMaterail.alpha = 0.8

    icoSphere.material = icoMaterail
    

    // 最后一步调用engine的runRenderLoop方案，
    // 执行scene.render()，让我们的3d场景渲染起来
    engine.runRenderLoop(() => {
      scene.render()
    })

    // 监听浏览器改变大小的事件，通过调用engine.resize()来自适应窗口大小
    window.addEventListener('resize', () => {
      engine.resize()
    })
  }

  onMounted(() => {
    initBabylon()
  })
</script>